//! 缠论分型、笔的识别与主流程
//!
//! 包含分型查找、笔识别、CZSC主类等核心逻辑

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use crate::objects::{
    bar::{NewBar, RawBar},
    bi::BI,
    enums::{Direction, Freq, Mark},
    fx::FX,
    zs::ZS,
};

/// 去除包含关系：输入三根K线，返回是否有包含关系和新的K线
pub fn remove_include(k1: &NewBar, k2: &NewBar, k3: &RawBar) -> (bool, NewBar) {
    // 检查k2是否包含k3
    let is_include = k2.high >= k3.high && k2.low <= k3.low;
    
    if is_include {
        // 包含关系，合并K线
        let new_bar = NewBar::new(
            k2.symbol.clone(),
            k2.id,
            k2.dt,
            k2.freq.clone(),
            k2.open,
            k3.close,
            k2.high.max(k3.high),
            k2.low.min(k3.low),
            k2.vol + k3.vol,
            k2.amount + k3.amount,
        );
        (true, new_bar)
    } else {
        // 无包含关系，直接返回k3转换的NewBar
        let new_bar = NewBar::new(
            k3.symbol.clone(),
            k3.id,
            k3.dt,
            k3.freq.clone(),
            k3.open,
            k3.close,
            k3.high,
            k3.low,
            k3.vol,
            k3.amount,
        );
        (false, new_bar)
    }
}

/// 查找分型：输入三根K线，返回分型对象或None
pub fn check_fx(k1: &NewBar, k2: &NewBar, k3: &NewBar) -> Option<FX> {
    // 1. 顶分型：k2的高低都大于k1和k3
    if k2.high > k1.high && k2.high > k3.high && k2.low > k1.low && k2.low > k3.low {
        Some(FX::new(
            k2.symbol.clone(),
            k2.dt,
            Mark::G,
            k2.high,
            k2.low,
            k2.high,
            vec![k1.clone(), k2.clone(), k3.clone()],
        ))
    // 2. 底分型：k2的高低都小于k1和k3
    } else if k2.high < k1.high && k2.high < k3.high && k2.low < k1.low && k2.low < k3.low {
        Some(FX::new(
            k2.symbol.clone(),
            k2.dt,
            Mark::D,
            k2.high,
            k2.low,
            k2.low,
            vec![k1.clone(), k2.clone(), k3.clone()],
        ))
    } else {
        None
    }
}

/// 查找所有分型：输入K线序列，返回分型序列
pub fn check_fxs(bars: &[NewBar]) -> Vec<FX> {
    // 至少需要3根K线才能形成分型
    if bars.len() < 3 {
        return vec![];
    }
    let mut fxs = Vec::new();
    for i in 1..bars.len() - 1 {
        if let Some(fx) = check_fx(&bars[i - 1], &bars[i], &bars[i + 1]) {
            fxs.push(fx);
        }
    }
    fxs
}

/// 查找笔：输入K线序列，返回笔序列
pub fn check_bi(bars: &[NewBar]) -> Vec<BI> {
    // 这里只实现最基础的笔识别流程，复杂逻辑可后续完善
    let fxs = check_fxs(bars);
    let mut bis = Vec::new();
    let mut i = 0;
    while i + 1 < fxs.len() {
        let fx_a = &fxs[i];
        let fx_b = &fxs[i + 1];
        // 方向必须不同，且分型之间至少隔一根K线
        if fx_a.mark != fx_b.mark && (fx_b.dt > fx_a.dt) {
            let direction = if fx_b.mark == Mark::G {
                Direction::Down
            } else {
                Direction::Up
            };
            let bi = BI::new(
                fx_a.symbol.clone(),
                fx_a.clone(),
                fx_b.clone(),
                vec![fx_a.clone(), fx_b.clone()],
                direction,
                vec![], // 这里 bars 可后续补充
            );
            bis.push(bi);
        }
        i += 1;
    }
    bis
}

/// CZSC主类，缠论主流程对象
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CZSC {
    /// K线序列
    pub bars: Vec<RawBar>,
    /// 笔序列
    pub bis: Vec<BI>,
    /// 分型序列
    pub fxs: Vec<FX>,
    /// 频率
    pub freq: Freq,
}

impl CZSC {
    /// 创建新的CZSC对象
    pub fn new(bars: Vec<RawBar>, freq: Freq) -> Self {
        // 初始化分型、笔等
        let mut czsc = Self { bars, bis: vec![], fxs: vec![], freq };
        // 如果有K线数据，进行初始化分析
        if !czsc.bars.is_empty() {
            czsc._init_analysis();
        }
        czsc
    }

    /// 初始化分析
    fn _init_analysis(&mut self) {
        // 这里可以添加初始化分析逻辑
        // 比如去除包含关系、识别分型、识别笔等
    }

    /// 更新K线数据
    pub fn update(&mut self, bar: RawBar) {
        self.bars.push(bar);
        // 这里可以添加实时更新逻辑
    }

    /// 生成ECharts图表
    pub fn to_echarts(&self, width: &str, height: &str, _bs: &[String]) {
        // TODO: 实现ECharts图表生成
        println!("生成ECharts图表: {}x{}", width, height);
    }

    /// 生成Plotly图表
    pub fn to_plotly(&self) {
        // TODO: 实现Plotly图表生成
        println!("生成Plotly图表");
    }

    /// 在浏览器中打开图表
    pub fn open_in_browser(&self, width: &str, height: &str) {
        // TODO: 实现在浏览器中打开图表
        println!("在浏览器中打开图表: {}x{}", width, height);
    }

    /// 获取最后一笔的延伸信息
    pub fn last_bi_extend(&self) -> Option<serde_json::Value> {
        if let Some(last_bi) = self.bis.last() {
            // TODO: 实现最后一笔延伸信息计算
            Some(serde_json::json!({
                "direction": last_bi.direction.to_string(),
                "high": last_bi.high(),
                "low": last_bi.low(),
                "power": last_bi.power_price()
            }))
        } else {
            None
        }
    }

    /// 获取已完成的笔
    pub fn finished_bis(&self) -> Vec<BI> {
        // TODO: 实现已完成笔的识别
        self.bis.clone()
    }

    /// 获取未完成笔的分型
    pub fn ubi_fxs(&self) -> Vec<FX> {
        // TODO: 实现未完成笔分型的识别
        vec![]
    }

    /// 获取未完成笔
    pub fn ubi(&self) -> Option<BI> {
        // TODO: 实现未完成笔的识别
        None
    }

    /// 获取分型列表
    pub fn fx_list(&self) -> Vec<FX> {
        self.fxs.clone()
    }

    /// 获取K线数量
    pub fn bar_count(&self) -> usize {
        self.bars.len()
    }

    /// 获取笔数量
    pub fn bi_count(&self) -> usize {
        self.bis.len()
    }

    /// 获取分型数量
    pub fn fx_count(&self) -> usize {
        self.fxs.len()
    }

    /// 获取统计信息
    pub fn get_stats(&self) -> serde_json::Value {
        serde_json::json!({
            "bar_count": self.bar_count(),
            "bi_count": self.bi_count(),
            "fx_count": self.fx_count(),
            "freq": self.freq.to_string()
        })
    }
}

impl std::fmt::Display for CZSC {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "CZSC(bars={}, bis={}, fxs={}, freq={})",
            self.bars.len(),
            self.bis.len(),
            self.fxs.len(),
            self.freq
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::Utc;

    #[test]
    fn test_czsc() {
        let bars = vec![
            RawBar::new(
                "000001.SZ".to_string(),
                1,
                Utc::now(),
                Freq::Day,
                10.0,
                11.0,
                12.0,
                9.0,
                1000.0,
                11000.0,
            ),
            RawBar::new(
                "000001.SZ".to_string(),
                2,
                Utc::now(),
                Freq::Day,
                11.0,
                10.0,
                12.0,
                9.0,
                1000.0,
                11000.0,
            ),
        ];

        let czsc = CZSC::new(bars, Freq::Day);
        assert_eq!(czsc.bar_count(), 2);
        assert_eq!(czsc.freq, Freq::Day);
    }
} 